#include "effect_engine/EffectEngine.h"
#include "effect_engine/filters/impl/ColorSeparationFilter.h"
#include "effect_engine/filters/impl/GrayFilter.h"
#include "effect_engine/filters/impl/OldGaussianBlurFilter.h"
#include "effect_engine/filters/impl/SurfaceBlurFilter.h"
#include "napi/native_api.h"
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <hilog/log.h>
#include <multimedia/image_framework/image_pixel_map_mdk.h>
#include <multimedia/image_framework/image_source_mdk.h>
#include <rawfile/raw_file.h>
#include <rawfile/raw_file_manager.h>
#include <stdlib.h>

static napi_value getSyncPixelMap(napi_env env, napi_callback_info info) {
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    napi_valuetype srcType;
    napi_typeof(env, args[0], &srcType);

    // 入参args[0]是资源管理器，用来初始化native层的资源管理器
    NativeResourceManager *mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, args[0]);

    size_t strSize;
    char srcBuf[2048];
    // 入参args[1]是文件名称
    napi_get_value_string_utf8(env, args[1], srcBuf, sizeof(srcBuf), &strSize);

    // 用资源管理器打开Raw文件
    RawFile *rawFile = OH_ResourceManager_OpenRawFile(mNativeResMgr, srcBuf);
    if (rawFile != NULL) {
        // 获取文件大小，并读取数据
        long len = OH_ResourceManager_GetRawFileSize(rawFile);
        uint8_t *data = static_cast<uint8_t *>(malloc(len));
        int res = OH_ResourceManager_ReadRawFile(rawFile, data, len);

        OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "[decode]", "ImageBuffer Size:%{public}d", len);

        OhosImageSource imageSource_c;
        imageSource_c.buffer = data;
        imageSource_c.bufferSize = len;

        OhosImageSourceOps ops{};
        napi_value imageSource;
        napi_value pixelMap;

        // 用读取到的Raw数据创建ImageSource
        int32_t ret = OH_ImageSource_Create(env, &imageSource_c, &ops, &imageSource);

        // 初始化native层的ImageSource
        ImageSourceNative *imageSourceNative_c = OH_ImageSource_InitNative(env, imageSource);
        OhosImageDecodingOps decodingOps{
            .editable = 1,
            .pixelFormat = 4,
        };
        // 创建pixelMap
        OH_ImageSource_CreatePixelMap(imageSourceNative_c, &decodingOps, &pixelMap);

        // 处理完毕，释放native层资源
        OH_ImageSource_Release(imageSourceNative_c);
        OH_ResourceManager_CloseRawFile(rawFile);
        return pixelMap;
    }
    OH_ResourceManager_ReleaseNativeResourceManager(mNativeResMgr);
    return nullptr;
}

napi_value Filter(napi_env env, napi_callback_info info) {
    napi_value thisVar = nullptr;
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    if (napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr)) {
        return nullptr;
    }
    napi_value result = nullptr;
    napi_get_undefined(env, &result);

    // 初始化NativePixelMap对象。
    NativePixelMap *native = OH_PixelMap_InitNativePixelMap(env, args[0]);
    if (native == nullptr) {
        return result;
    }

    size_t strSize;
    char filterName[256];
    napi_get_value_string_utf8(env, args[1], filterName, sizeof(filterName), &strSize);
    OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "[doFilter]", "Filter:%{public}s", filterName);

    // 获取图片信息。
    struct OhosPixelMapInfos pixelMapInfo;
    OH_PixelMap_GetImageInfo(native, &pixelMapInfo);

    // 获取PixelMap对象每行字节数。
    int32_t rowBytes;
    OH_PixelMap_GetBytesNumberPerRow(native, &rowBytes);

    // 获取PixelMap对象是否可编辑的状态。
    int32_t editable = 0;
    OH_PixelMap_GetIsEditable(native, &editable);

    // 获取PixelMap对象是否支持Alpha通道。
    int32_t supportAlpha = 0;
    OH_PixelMap_IsSupportAlpha(native, &supportAlpha);

    // 获取PixelMap对象数据的内存地址，并锁定该内存。
    void *pixelAddr = nullptr;
    OH_PixelMap_AccessPixels(native, &pixelAddr);
    EffectEngine effectEngine;
    effectEngine.Init();


    ImageInfo input;
    input.width = pixelMapInfo.width;
    input.height = pixelMapInfo.height;
    input.channels = pixelMapInfo.pixelFormat;
    input.bytesPerLine = pixelMapInfo.rowSize;
    input.data = pixelAddr;
    ImageInfo output;
    output.width = pixelMapInfo.width;
    output.height = pixelMapInfo.height;
    output.channels = pixelMapInfo.pixelFormat;
    output.bytesPerLine = pixelMapInfo.rowSize;
    output.data = pixelAddr;
    if (strcmp(filterName, "gray") == 0) {
        const auto filter = std::make_shared<GrayFilter>();
        filter->SetRedFactor(0.299);
        filter->SetGreenFactor(0.587);
        filter->SetBlueFactor(0.114);
        effectEngine.Process(input, output, filter);
    } else if (strcmp(filterName, "gaussian") == 0) {
        const auto filter = std::make_shared<OldGaussianBlurFilter>();
        filter->SetRadius(128);
        effectEngine.Process(input, output, filter);
    } else if (strcmp(filterName, "color_separation") == 0) {
        const auto filter = std::make_shared<ColorSeparationFilter>();
        filter->SetRedOffsetX(100);
        filter->SetGreenOffsetX(200);
        filter->SetBlueOffsetX(300);
        effectEngine.Process(input, output, filter);
    } else if (strcmp(filterName, "surface_blur") == 0) {
        const auto filter = std::make_shared<SurfaceBlurFilter>();
        filter->SetBlurRadius(60);
        filter->SetThreshold(128);
        effectEngine.Process(input, output, filter);
    }

    // 释放PixelMap对象数据的内存锁。
    OH_PixelMap_UnAccessPixels(native);

    return result;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"getSyncPixelMap", nullptr, getSyncPixelMap, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"doFilter", nullptr, Filter, nullptr, nullptr, nullptr, napi_default, nullptr},
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void *)0),
    .reserved = {0},
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
